package control;

import java.util.Vector;

import storage.ManageData;
import domain.PaymentMethod;

import basic.CRUDable;
import basic.Manager;

//@author A0098891H
public class PaymentMethodManager extends Manager{
	private Vector<PaymentMethod> _listOfPaymentMethod;

	/**
	 * @param o
	 */
	public PaymentMethodManager(Object o)
	{
		this.initialize();
	}

	/**
	 * 
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	public Vector<PaymentMethod> getList()
	{
		return this._listOfPaymentMethod;
	}
	
	/**
	 *
	 * @see basic.Manager#add(basic.CRUDable)
	 * @param payMethod
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public int add(CRUDable payMethod) {

		//check uniqueness
		for(PaymentMethod p:_listOfPaymentMethod)
		{
			if(p.equals((PaymentMethod)payMethod))
				return -1;
		}
		payMethod.set_id(_nextId++);
		_listOfPaymentMethod.add((PaymentMethod)payMethod);
		return payMethod.get_id();
	}

	/**
	 *
	 * @see basic.Manager#addTo(basic.CRUDable, int, int)
	 * @param payMethod
	 * @param id
	 * @param pos
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean addTo(CRUDable payMethod, int id, int pos) {
		//check uniqueness
		for(PaymentMethod p:_listOfPaymentMethod)
		{
			if(p.equals((PaymentMethod)payMethod))
				return false;
		}
		payMethod.set_id(id);
		_listOfPaymentMethod.add(pos,(PaymentMethod)payMethod);

		return false;
	}

	/**
	 *
	 * @see basic.Manager#get(int)
	 * @param id
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public PaymentMethod get(int id) {

		for(PaymentMethod p: _listOfPaymentMethod)
		{
			if(p.get_id()==id)
			{
				return p;
			}
		}
		return this._listOfPaymentMethod.get(0);
	}

	/**
	 *
	 * @see basic.Manager#edit(int, basic.CRUDable)
	 * @param id
	 * @param payMethod
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public PaymentMethod edit(int id, CRUDable payMethod) {

		for(PaymentMethod p:_listOfPaymentMethod)
		{
			if(p.equals((PaymentMethod)payMethod) && p.get_id()!=id)
				return null;
		}
		for(PaymentMethod p:_listOfPaymentMethod)
		{
			if(p.get_id()==id)
			{
				PaymentMethod pay = new PaymentMethod(p);
				p.set((PaymentMethod)payMethod);
				return pay;
			}
		}
		return null;
	}

	/**
	 *
	 * @see basic.Manager#delete(int)
	 * @param id
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public PaymentMethod delete(int id) {
		if(id==0)
			return null;
		for(PaymentMethod p:_listOfPaymentMethod)
		{
			if(p.get_id()==id)
			{
				if(this._listOfPaymentMethod.remove(p))
					return p;
				else 
					return null;
			}
		}
		return null;
	}

	public int deleteFrom(int id) {
		if(id==0)
			return -1;
		int i=0;
		for(PaymentMethod p:_listOfPaymentMethod)
		{
			if(p.get_id()==id)
			{
				if(this._listOfPaymentMethod.remove(p))
					return i;
				else 
					return -1;
			}
			i++;
		}
		return -1;
	}
	/**
	 * 
	 * @param payManager
	 * @Precondition 
	 * @Postcondition 
	 */
	public void set(PaymentMethodManager payManager)
	{
		super.set(payManager);
		this._listOfPaymentMethod = payManager._listOfPaymentMethod;
	}
	/**
	 *
	 * @see basic.Manager#initialize()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean initialize()
	{	
		if(loadAll()==false)
		{
			super.initialize();
			_listOfPaymentMethod = new Vector<PaymentMethod>();
			PaymentMethod pay = new PaymentMethod("SAVING ACCOUNT");
			add(pay);

			String [] initPay = {"CASH","CREDIT CARD", "DEBIT CARD","CASH CARD" ,"NETS", 
					"INTERNET BANKING" ,"EZLINK", "GIRO"};
			for(String name: initPay)
			{
				PaymentMethod pm = new PaymentMethod();
				pm.set_name(name);
				add(pm);
			}
			
			
		}
		return true;
	}

	/**
	 *
	 * @see basic.Manager#saveAll()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean saveAll() {
		return ManageData.savePaymentManagerToFile(this);
	}

	/**
	 *
	 * @see basic.Manager#loadAll()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean loadAll() {
		PaymentMethodManager payManager = ManageData.loadPaymentManagerFromFile();
		if(payManager==null)
		{
			return false;
		}
		this.set(payManager);
		return true;
	}
	/**
	 *
	 * @see interfaces.CommandLine#readCmd(java.lang.String)
	 * @param cmd
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public int readCmd(String cmd) {
		//<PAYMENTMETHOD>|<ADD> <NAME> (COMPULSORY)
		//<PAYMENTMETHOD>|<EDIT> <ID> <NAME> (COMPULSORY) 
		
		//<PAYMENTMETHOD>|<DELETE> <ID>
		//<PAYMENTMETHOD>|<VIEW> <ID>
		//<PAYMENTMETHOD>|<UNDO>
	
		//check undo
		boolean isUndo = false;
		boolean isRedo = false;
		if(cmd.trim().compareToIgnoreCase("undo")==0)
		{
			if(!_undoStack.isEmpty())
			{
				isUndo = true;
				cmd = _undoStack.pop();
				int iAction = cmd.indexOf('[');
				int isavedId = cmd.indexOf('&');
				int isavedPos = cmd.indexOf(']');
				_undoAction = Integer.parseInt(cmd.substring(0, iAction));
				_savedId = Integer.parseInt(cmd.substring(iAction+1, isavedId));
				_savedPos = Integer.parseInt(cmd.substring(isavedId+1, isavedPos));

				if(_undoAction==ACTION_DELETE || _undoAction==ACTION_EDIT)
				{
					_redoStack.add(cmd.substring(0,cmd.indexOf('|')));
					cmd = cmd.substring(cmd.indexOf('|')+1);
				}
			}
		}
		else if(cmd.trim().compareToIgnoreCase("redo")==0)
		{
			if(!_redoStack.isEmpty())
			{
				isRedo = true;
				cmd = _redoStack.pop();
				if(cmd.indexOf(']')!=-1)
				{
					int iAction = cmd.indexOf('[');
					int isavedId = cmd.indexOf('&');
					int isavedPos = cmd.indexOf(']');
					_undoAction = Integer.parseInt(cmd.substring(0, iAction));
					_savedId = Integer.parseInt(cmd.substring(iAction+1, isavedId));
					_savedPos = Integer.parseInt(cmd.substring(isavedId+1, isavedPos));
					cmd = cmd.substring(cmd.indexOf(']')+1);
				}
			}	
		}
		
		String str[] = cmd.split(",");
		for(int i=0;i<str.length;i++)
		{
			str[i] = str[i].trim();
		}
		int length = str.length;
		
		if(length < 2)
			return -1;

		switch(str[1].toLowerCase())
		{
		case "add":
			if(length < 3) 
				return -1;
			PaymentMethod payMethod = new PaymentMethod();
			payMethod.set_name(str[2]);
			_returnedObject =  payMethod;

			if(isUndo && _undoAction==ACTION_ADD)
			{
				int _savedPos = deleteFrom(_savedId);
				if(_savedPos >= 0)
				{//must record the position and id for redo
					_redoStack.add(-1+"["+_savedId+"&"+_savedPos+"]"+cmd);
					return _undoAction;
				}
				else
					return -1;//undo failed
			}
			if(isUndo && _undoAction==ACTION_DELETE)
			{
				if(!addTo(payMethod,_savedId,_savedPos))
					return -1;
				return _undoAction;
			}

			if(isRedo)
			{
				if(!addTo(payMethod,_savedId,_savedPos))
					return -1;
			}
			else
			{
				_savedId = add(payMethod);
			}
			if(_savedId<0)
				return -1;
			_action = ACTION_ADD;
			
			break;
		case "delete":
			if(length < 3)
				return -1;
			_savedId = Integer.parseInt(str[2]);
			PaymentMethod deletedPayMethod = get(_savedId);
			if(deletedPayMethod==null)
				return -1;
			_savedPos = this._listOfPaymentMethod.indexOf(deletedPayMethod);
			deletedPayMethod = delete(_savedId);
			if(deletedPayMethod==null)
				return -1;
			_returnedObject = deletedPayMethod;
			cmd+="|payment method,add,"+deletedPayMethod.writeToString();
			_action = ACTION_DELETE;
			break;
			
		case "edit":
			if(length < 4)
				return -1;
			_savedId = Integer.parseInt(str[2]);
			PaymentMethod updatedPayMethod = new PaymentMethod();
			updatedPayMethod.set_name(str[3]);
			PaymentMethod obsoletePayMethod = edit(_savedId,updatedPayMethod);
			if(obsoletePayMethod==null)
				return -1;
			_returnedObject = obsoletePayMethod;
			if(isUndo && _undoAction==ACTION_EDIT)
			{
				return _undoAction;
			}
			cmd+="|payment method,edit,"+_savedId+","+obsoletePayMethod.writeToString();
			_action = ACTION_EDIT;
			break;
		default:
			return -1;
		}

		_undoStack.add(_action+"["+ _savedId +"&"+ _savedPos +"]"+cmd);
		
		return _action;
	}
	/**
	 * 
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	public int size()
	{
		return _listOfPaymentMethod.size();
	}
	
	/**
	 *
	 * @see java.lang.Object#toString()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	public String toString()
	{
		StringBuilder sb = new StringBuilder();
		for(PaymentMethod pm : this._listOfPaymentMethod)
		{
			sb.append("  ("+pm.get_id()+") "+pm.toString() + "\n");
		}
		return sb.toString();
	}
}
